параллельное программирование C++
Разработать программу, загружающую два параллельно работающих процесса, выводящих в свои окна указанные графические данные
Задание
Задание1: Параллельные процессы
Разработать программу, загружающую два параллельно работающих
процесса, выводящих в свои окна указанные графические данные
Окружность и прямоугольник
Область вывода состоит из двух окон: верхнего и нижнего в нечетных
вариантах или левого и правого в четных вариантах. Каждый процесс выводит в свое окно фигуры заданного вида, у которых случайно изменяются цвет,
размеры и положение.
Задание 2: Распараллеливание рекурсивных подпрограмм
Разработать программу, решающую данную задачу с помощью
рекурсивной функции. Преобразовать эту функцию и главную программу в много потоковуюпрограмму. Потоковые функции выполняются со случайной задержкой.
Вариант 1: Вычисление значений многочлена
sin(x)\approx\sum_k^n \frac{(-1)^{k}x^{2k+1}}{(2k+1)!}
по схеме Горнера методом сдваивания.
1.1 Параллельные процессы
Исходный код программы:
Первый процесс:
#include <windows.h> //заголовочный файл для win32 приложений
#pragma hdrstop
#define SizeWindow 400 //размер окна
MSG msg; //сообщение
HDC hdc; //контекст устройства
HBRUSH hBrush; //тип кисти
HWND Wnd; //handle окна
WNDCLASS wnds; //структура класса окна
char ClassName[255]="Rectangle"; //имя класса окна
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){//оконная функция
switch(uMsg) //обработчик сообщений
{
case WM_DESTROY: //выход
PostQuitMessage(0); return 0;
case WM_TIMER: //сработал таймер и нарисовали произвольный четырёхугольник
Rectangle(hdc, rand() %SizeWindow, rand()%SizeWindow/2, rand()%SizeWindow, rand()%SizeWindow); //нарисовали произвольный четырёхугольник
default: //по умолчанию
DefWindowProc(hWnd, uMsg, wParam, lParam);
break;
}
}
int WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int){
//регистрация класса окна в системе
wnds.style =CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS;
wnds.lpfnWndProc =WindowProc;
wnds.cbClsExtra =0;
wnds.cbWndExtra =0;
wnds.hInstance =hInstance;
wnds.hIcon =LoadIcon(0, IDI_APPLICATION);
wnds.hCursor =LoadCursor(0, IDC_ARROW);
wnds.hbrBackground=(HBRUSH) 6;
wnds.lpszMenuName =0;
wnds.lpszClassName=ClassName; //атрибуты структуры окна заполнены
RegisterClass(&wnds); //зарегистрируем класс окна
Wnd=CreateWindowEx(0, ClassName,
"Процесс1: Прямоугольники",
WS_EX_DLGMODALFRAME,
GetSystemMetrics(SM_CXFULLSCREEN)/2 - SizeWindow,
GetSystemMetrics(SM_CXFULLSCREEN)/2 - SizeWindow,
SizeWindow, SizeWindow/2,
0,0,hInstance,0); //создадим экземпляр зарегистрированного класса окна
ShowWindow(Wnd,SW_SHOWNORMAL); //отобразим окно на экране
hdc=GetDC(Wnd); //получим его контекст
SetTimer(Wnd,1,100,NULL); //установим таймер
int Exit=1;
while(Exit)
{ //обработка сообщений от окна
if((Exit=GetMessage(&msg,0,0,0)) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
Второй процесс
#include <windows.h> //заголовочный файл для win32 приложений
#pragma hdrstop
#define SizeWindow 400 //размер окна
MSG msg; //сообщение
HDC hdc; //контекст устройства
HBRUSH hBrush; //тип кисти
HWND Wnd; //handle окна
WNDCLASS wnds; //структура класса окна
char ClassName[255]="Circle"; //имя класса окна
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){//оконная функция
int x,y,r; //координаты центра и радиус окружности
switch(uMsg)
{
case WM_DESTROY: //выход
PostQuitMessage(0); return 0;
case WM_TIMER: //таймер
//генерируем координаты и радиус и рисуем эллипс
x = rand()%SizeWindow; y = rand()%SizeWindow; r = rand()%SizeWindow/4;
Ellipse(hdc,x-r, y+r,x+r,y-r);
default: //по умолчанию
DefWindowProc(hWnd,uMsg,wParam,lParam);
break;
}
}
int WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int){
//регистрация класса окна в системе
wnds.style =CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS;
wnds.lpfnWndProc =WindowProc;
wnds.cbClsExtra =0;
wnds.cbWndExtra =0;
wnds.hInstance =hInstance;
wnds.hIcon =LoadIcon(0, IDI_APPLICATION);
wnds.hCursor =LoadCursor(0, IDC_ARROW);
wnds.hbrBackground=(HBRUSH) 6;
wnds.lpszMenuName =0;
wnds.lpszClassName=ClassName; //атрибуты структуры окна заполнены
RegisterClass(&wnds); //зарегистрируем класс окна
Wnd=CreateWindowEx(0, ClassName,"Процесс2:Окружности",
WS_EX_DLGMODALFRAME,
GetSystemMetrics(SM_CXFULLSCREEN)/2-SizeWindow,GetSystemMetrics(SM_CXFULLSCREEN)/2 - 1.75*SizeWindow,
SizeWindow, SizeWindow/2,0,0,hInstance,0); //создадим экземпляр зарегистрированного класса
ShowWindow(Wnd,SW_SHOWNORMAL); //отобразим окно на экране
hdc=GetDC(Wnd); //получим его контекст
SetTimer(Wnd,1,100,NULL); //установим для него таймер
int Exit=1;
while(Exit) //обработка сообщений от окна
{
if((Exit=GetMessage(&msg,0,0,0)) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
Основной процесс
#include <windows.h> //заголовочный файл для win32 приложений
#include <string.h> //заголовочный файл для работы со строками
#include <stdio.h> //заголовочный файл для ввода-вывода
//идентификаторы, используемые в программе
#define ID_PROCESS 3
#define ID_KILLPROC 2
#define ID_EXIT 4
#define ID_HELP 1
#define PROCMAX 2
#define MAINMENU 1
#define IDI_ICON1 1
//прототип оконной функции
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
char szWinName[] = "main"; //имя окна
char str[255]; //буфер
int maxX,maxY; //максимальные значения Х и У
int X=0, Y=0;
int procnum = 0; //номер процесса
HDC memdc; //контекст окна
HBITMAP hbit; //handle картинки
HBRUSH hbrush; //тип кисти
PROCESS_INFORMATION pinfo[PROCMAX]; //массив структур информации
//о процессах
//главная функция приложения
int WINAPI WinMain( HINSTANCE hThisInst, HINSTANCE hPrevinst, LPSTR lpszArgs, int nWinMode)
{
HWND hwnd; //handle окна
MSG msg; //сообщение
WNDCLASS wcl; //класс окна
HANDLE hAccel=NULL; //акселераторы
//регистрируем новый класс окна в системе
wcl.hInstance = hThisInst;
wcl.lpszClassName = szWinName;
wcl.lpfnWndProc = WindowFunc;
wcl.style = 0;
wcl.hIcon =LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON1));
wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
wcl.lpszMenuName = (LPSTR)MAKEINTRESOURCE(MAINMENU);
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
if(!RegisterClass(&wcl)) return 0; //класс окна зарегистрирован
//создадим экземпляр нового класса
hwnd = CreateWindow(szWinName,
"Лабораторная работа №1, Вариант 1, ПП",
WS_OVERLAPPEDWINDOW,GetSystemMetrics(SM_CXFULLSCREEN)/2-400,GetSystemMetrics(SM_CXFULLSCREEN)/2-200,450,150,//150,370,450,150,
HWND_DESKTOP, NULL, hThisInst, NULL);
ShowWindow(hwnd,nWinMode); UpdateWindow(hwnd); //отобразим его на экране
while(GetMessage(&msg,NULL,0,0)) //обработка сообщений от окна
{
if(!TranslateAccelerator(hwnd,(HACCEL)hAccel,&msg))
{
TranslateMessage(&msg); DispatchMessage(&msg);
}
}
return msg.wParam;
}
//оконная функция
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc; //контекст
PAINTSTRUCT paintstruct; //структура для рисования
TEXTMETRIC tm;
STARTUPINFO startin; //структура для запуска процессов
switch(message)
{
case WM_CREATE: //если окно создаётся, заполним область вывода белым цветом
maxX = GetSystemMetrics(SM_CXSCREEN);
maxY = GetSystemMetrics(SM_CYSCREEN);
hdc = GetDC(hwnd);
memdc = CreateCompatibleDC(hdc);
hbit = CreateCompatibleBitmap(hdc,maxX,maxY);
SelectObject(memdc,hbit);
hbrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
SelectObject(memdc,hbrush);
PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
ReleaseDC(hwnd,hdc);
break;
case WM_COMMAND: //если нажата одна из опций меню
switch (LOWORD (wParam))
{
case ID_PROCESS: //открыть процесс
{
if(procnum==PROCMAX) //если их два, то больше нельзя
{
MessageBox(hwnd,"Запущены оба процесса", "Ошибка", MB_OK);
break;
};
char TestName[]="PP_lab1_process .exe"; //здесь создаётся имя для запуска
TestName[15]=procnum+49;
//заполним структуру STARTUPINFO
startin.cb = sizeof(STARTUPINFO);
startin.lpReserved = NULL;
startin.lpDesktop = NULL;
startin.lpTitle = NULL;
startin.dwFlags = STARTF_USESHOWWINDOW;
startin.cbReserved2 = 0;
startin.lpReserved2 = NULL;
startin.wShowWindow = SW_SHOWNORMAL;
//запускаем новый процесс
if (CreateProcess(NULL, TestName ,NULL,NULL,FALSE,0,
NULL,NULL,&startin, &(pinfo[procnum])))
{
//вывод в главное окно, что процесс создан
GetTextMetrics(memdc,&tm);
sprintf(str,"Процесс %d создан",procnum);
TextOut(memdc,X,Y,str,strlen(str));
Y = Y + tm.tmHeight+tm.tmExternalLeading;
InvalidateRect(hwnd,NULL,1);
//перерисуем окно
procnum++;
}
else MessageBox(hwnd,"Не найдена тестовая программа!","Ошибка",MB_OK);
}
break;
case ID_KILLPROC: //закрыть процесс
if(procnum) procnum--; //декремент количества процессов
else
{ //если нечего закрывать
MessageBox(hwnd,"Все процессы закрыты","Ошибка",MB_OK);
break;
}
GetTextMetrics(memdc,&tm);
//функция завершает процесс
TerminateProcess(pinfo[procnum].hProcess,0);
//вывод в главное окно, что процесс завершён
sprintf(str,"Процесс %d завершен",procnum);
TextOut(memdc,X,Y,str,strlen(str));
Y = Y+tm.tmHeight+tm.tmExternalLeading;
InvalidateRect(hwnd,NULL,1);
break;
case ID_EXIT: //Выход
{
TerminateProcess(pinfo[0].hProcess,0);TerminateProcess(pinfo[1].hProcess,0);
DeleteDC(memdc); PostQuitMessage(0);
}
break;
} break;
case WM_PAINT: //перерисовка окна
hdc = BeginPaint(hwnd,&paintstruct);
BitBlt(hdc,0,0,maxX,maxY,memdc,0,0,SRCCOPY);
EndPaint(hwnd,&paintstruct);
break;
case WM_DESTROY: //если нажата кнопка, закрыть
DeleteDC(memdc);
PostQuitMessage(0);
break;
default: // по умолчанию
return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}
Результат работы программы:
1.2 Распараллеливание рекурсивных подпрограмм
Исходный код программы:
#include <windows.h>
#include <time.h> // получение первого случайного числа
#include <iostream> // ввод-вывод
#include <conio.h> // для включения ожидания ввода клавиши
using namespace std;
#define N 10 // степень многочлена
double x; // значение переменной
struct arg // структура для передачи параметров
{
int l, r; // нижний и верхний номера 2х2=матрицы
double p, q; // коэффициенты первой строки матрицы
};
double a[2*N+2]; // коэффициенты многочлена
DWORD WINAPI prod(void* s) // функция потока
{
int i, l=((arg *)s) -> l, r=((arg *)s) -> r;
Sleep(rand()%1000); // случайная задержка
if (l == r)
{
((arg *)s) -> p = x; // установка
((arg *)s) -> q = a[l]; // коэффициентов
}
else
{
arg *r1 = new arg, *r2 = new arg;
HANDLE H[2]; // дескрипторы потоков
r1 -> l = l; r1 -> r = (l + r + 1)/2 - 1; //установка границ
r2 -> l = (l + r + 1)/2; r2 -> r = r;
H[0] = CreateThread(0,0,prod, (void *)r1,0,0); // порождение
H[1] = CreateThread(0,0,prod, (void *)r2,0,0); // потоков
for (i = 0; i < 2; i++) WaitForSingleObject(H,INFINITE); // ожидание выполнения потоков
((arg *)s) -> p = (r1 -> p)*(r2 -> p); //p1*p2
((arg *)s) -> q = (r1 -> p)*(r2 -> q)+(r1 -> q);//p1*q2+q1
delete r1; delete r2;
}
return 1;
}
double fact(double f)
{
if(f==0||f==1) return(1);
return(f*fact(f-1));
}
void main()
{
int i; double w=0, z;
srand(time(NULL));//Включение генератора с.ч.
for (i=0; i <=2*N+1; i=i+2) a[i] = 0; // установка коэффициентов перед x с чётной степенью
for (i=0; i <=N; i++) a[2*i+1] = pow(-1.0,(i))/fact(2*i+1); // установка коэффициентов перед x С нечётной степенью
arg t; // объявление структуры параметров
for (x = 1; x <10; x++) //перебор значений х
{
t.l = 0; t.r = 2*N+1; // границы массива матриц
prod(&t); // вызов подпрограммы
cout <<"x=" << x << " Polynom value = " << t.q<<endl; // вывод
z = 0;
for (i = 0; i <= N; i++) // цикл для проверки
//вычисление правой части выражения
{ z+=pow(-1.0,i)*pow(x,2*i+1)/fact(2*i+1); }
cout <<"\tsin(x)=\t\t" <<sin(x)<<"\n\tRight part=\t"<<z<<endl; // вывод значения для проверки
getch(); // ожидание нажатия клавиши
}
}
[I]Результат работы программы:
Комментарии 0 2017-06-16 01:34:49